<template>
  <ie-page class="district">

    <div class="ie-table">

      <section>
        <div class="head">
          <p class="h">请选择组织</p>
          <p><icon-exclamation-circle />仅可在类型的叶节点添加辖区</p>
        </div>

        <a-cascader
          v-model:model-value="department_id"
          :options="options"
          :style="{ width: '400px' }"
          placeholder="请选择..."
        />
      </section>

      <section>
        <div class="head">
          <p class="h">请设置辖区</p>
          <p><icon-exclamation-circle />仅允许使用一级辖区</p>
        </div>

        <a-spin v-if="isFetching" />

        <a-tree
          v-else-if="treeData.length"
          :data="treeData"
          size="large"
          block-node
        >
          <template #extra="nodeData">
            <a-space>
              <a-button
                v-if="nodeData.department_id"
                status="success"
                size="mini"
                @click="handleInsert(nodeData)"
              >新增</a-button>
              <template v-else>
                <a-button status="warning" size="mini" @click="handleUpdate(nodeData)">修改</a-button>
                <a-popconfirm
                  content="删除将会同时移除其子节点，请确定是否删除？"
                  position="tr"
                  @before-ok="done => handleRemove(nodeData, done)"
                >
                  <a-button status="danger" size="mini">删除</a-button>
                </a-popconfirm>
              </template>
            </a-space>
          </template>
        </a-tree>

        <a-empty
          v-else-if="department_id"
          description="当前类型下没有辖区"
        />

      </section>
    </div>

    <a-modal
      v-model:visible="visible"
      :title="formValue.id ? '修改辖区' : '新增辖区'"
      title-align="start"
      @before-ok="handleOk"
      @ok="handleCancel"
      @cancel="handleCancel"
    >
      <a-form
        :model="formValue"
        @submit="handleSubmit"
        layout="vertical"
        size="large"
        ref="formRef"
      >
        <a-form-item
          label="辖区名称"
          field="name"
          :rules="[
            { required: true, message: '辖区名称不可为空' }
          ]"
          :validate-trigger="['change', 'input', 'blur']"
        >
          <a-input
            v-model="formValue.name"
            placeholder="请输入辖区名称"
            allow-clear
          />
          <template v-if="!formValue.id && formValue.department_id" #extra>
            <div>在 {{ parentNodeRef.title }} 下增加辖区</div>
          </template>
        </a-form-item>
      </a-form>
    </a-modal>
  </ie-page>
</template>

<script setup>
import { computed, ref, watch } from 'vue'
import { useQuery, useMutation } from 'villus'
import { cloneDeep } from 'lodash-es'
import gql from 'graphql-tag'

import { noop, makeUpOptions, makeUpTree } from '/@/utils/helper'
import { IconExclamationCircle } from '@arco-design/web-vue/es/icon'

const department_id = ref()
const department_list = ref([])

const options = computed(() => {
  return makeUpOptions(department_list.value)
})
const department = computed(() => {
  if (department_id.value) {
    return department_list.value.find(({ id }) => id === department_id.value)
  }
})

useQuery({
  query: gql`
    query {
      department (order_by: { create_at: asc }) {
        id
        name
        parent_id
      }
    }
  `
}).then(({ data, error }) => {
  if (!error.value) {
    department_list.value = data.value.department || []
  }
})

const { data, isFetching } = useQuery({
  query: gql`
    query ($id: Int!) {
      district (
        where: { department_id: { _eq: $id } }
        order_by: { create_at: asc }
      ) {
        id
        name
      }
    }
  `,
  variables: computed(() => {
    return { id: department_id.value }
  }),
  fetchOnMount: false
})

const treeData = ref([])

watch(
  () => data.value?.district,
  districts => {
    if (department.value?.id) {
      treeData.value = [{
        title: department.value.name,
        key: 'department_' + department.value.id,
        department_id: department.value.id,
        children: Array.isArray(districts)
          ? makeUpTree(districts || [])
          : []
      }]
    }
  }, { immediate: true }
)

const { execute: insert } = useMutation(gql`
  mutation ($object: district_insert_input!) {
    insert_district (
      objects: [$object]
    ) {
      returning {
        id
        name
        department_id
      }
    }
  }
`)
const { execute: update } = useMutation(gql`
  mutation ($id: Int!, $name: String!) {
    update_district_by_pk (
      pk_columns: { id: $id },
      _set: { name: $name }
    ) {
      id
      name
      department_id
    }
  }
`)
const { execute: remove } = useMutation(gql`
  mutation ($id: Int!) {
    delete_district_by_pk (id: $id) {
      id
    }
  }
`)

const visible = ref(false)
const formRef = ref()
const formInitValue = {
  id: null,
  department_id: null,
  name: ''
}
const formValue = ref(cloneDeep(formInitValue))
const parentNodeRef = computed(() => {
  return formValue.value.department_id
    && treeData.value.find(item => item.department_id === formValue.value.department_id)
})

function handleInsert(nodeData) {
  if (department_id.value) {
    formValue.value.department_id = department_id.value
  }

  visible.value = true
}

function handleUpdate(nodeData) {
  const id = nodeData?.key

  if (id) {
    formValue.value.id = id
    formValue.value.name = nodeData?.title
  }

  visible.value = true
}

function handleRemove(nodeData, done = noop) {
  const { key: id } = nodeData || {}

  if (id) {
    return remove({
      id
    }).then(res => {
      if (!res.errors) {
        const children = treeData.value[0]?.children

        if (Array.isArray(children)) {
          const index = children.findIndex(item => item.key === id)

          if (index > -1) {
            children.splice(index, 1)
          }
        }
      }
      done()
    })
  }
  done()
}

function handleSubmit({ values, errors }, done = noop) {
  if (!errors) {
    function callback(res) {
      if (!res.errors) {
        const data = res.data?.insert_district?.returning ||
          [res.data?.update_district_by_pk || {}]
        const [{ id, name }] = data
        const children = treeData.value[0]?.children

        if (id && Array.isArray(children)) {
          const index = children.findIndex(item => item.key === id)

          if (index > -1) {
            children[index] = {
              ...children[index],
              title: name
            }
          } else {
            children.push({
              title: name,
              key: id
            })
          }
        }
      }
      done()
    }

    return values.id
      ? update({
          id: values.id,
          name: values.name
        }).then(callback)
      : insert({ object: {
        department_id: values.department_id,
        name: values.name
      }}).then(callback)
  }

  done(false)
}

function handleCancel() {
  if (formRef.value?.resetFields) {
    formRef.value?.resetFields()
  }
  formValue.value = cloneDeep(formInitValue)
}

function handleOk(done) {
  if (formRef.value?.handleSubmit) {
    formRef.value?.handleSubmit(done)
  }
}
</script>


<style lang="less">
.district {

  section {
    margin-bottom: 48px;

    .head {

      p {
        font-size: 13px;
        color: rgb(78, 89, 105);
      }

      .h {
        font-size: 16px;
        line-height: 24px;
        margin-bottom: 8px;
        font-weight: bold;
        color: #323237;
      }

      .arco-icon {
        margin-right: 4px;
      }
    }
  }
}
</style>